
import Constants from './const';

/*
- 可以吃掉对方棋子（+5000）
- 可以移动到终点（+4500）
- 可以从基地起飞（+4000）
- 可以移动到彩色通道（+1400）
- 可以移动到保护格子（+1200）
- 处于彩色通道，且可以往前移动（+1000）
- 当前格子后方 2*6 个格子有其他敌机（逃命）（+500）
- 当前格子前方 2*6 个格子有其他敌机（追杀）（+500）
- 移出保护格子（-700）
- 移到敌机前方 6 个格子（-300）
- 移到敌机前方 2*6 个格子（-100）
- 按规则随机选择棋子移动（+0）
*/

const LudoAI = {
  // 可以吃掉对方棋子
  canEat(side, chesses, pos, dice) {
    if (pos === -1) return false; // 还未起飞，不可能吃掉敌机

    const target_pos = pos + dice;
    const pub_pos = Constants.priPos2PubPos(target_pos, side);
    if (Constants.GUARD_POSITIONS.indexOf(pub_pos) !== -1 || // 在保护点不能吃掉其他棋子
      target_pos >= Constants.GRID_POSITIONS.length - 1) { // 在彩色通道不能吃掉其他棋子
      return false;
    }

    for (const symbol in chesses) {
      if (side === symbol) continue; // 跳过己方

      for (const opponent_pos of chesses[symbol]) {
        const opponent_pub_pos = Constants.priPos2PubPos(opponent_pos, symbol);
        if (pub_pos === opponent_pub_pos) {
          return true;
        }
      }
    }

    return false;
  },
  // 可以移动到终点
  canMoveToEndPoint(pos, dice) {
    return pos !== -1 && pos + dice === Constants.TOTAL_GRIDS - 1;
  },
  // 可以从基地起飞
  canLaunch(pos, dice) {
    return pos === -1 && dice === 6;
  },
  // 可以移动到彩色通道
  canMoveToTunnel(pos, dice) {
    return pos !== -1 && !Constants.isInTunnel(pos) && Constants.isInTunnel(pos + dice);
  },
  // 可以移动到保护格子
  canMoveToGuard(side, pos, dice) {
    if (pos === -1) return false; // 不可能从基地走到保护格子

    const target_pos = pos + dice;
    const pub_pos = Constants.priPos2PubPos(target_pos, side);
    return Constants.GUARD_POSITIONS.indexOf(pub_pos) !== -1;
  },
  // 处于彩色通道，且可以往前移动
  canMoveInTunnel(pos, dice) {
    if (pos === -1) return false; // 不在彩色通道

    const target_pos = pos + dice;
    return Constants.isInTunnel(pos) &&
      target_pos <= Constants.TOTAL_GRIDS - 1;
  },
  // 当前格子后方 2*6 个格子有其他敌机（逃命）
  runAway(side, chesses, pos) {
    return this.moveAheadOpponent(side, chesses, pos, 0, 2 * 6);
  },
  // 当前格子前方 2*6 个格子有其他敌机（追杀）
  runAfter(side, chesses, pos) {
    return this.moveAheadOpponent(side, chesses, pos, 0, -2 * 6);
  },
  // 移出保护格子
  shiftOutGuard(side, pos, dice) {
    if (pos === -1) return false; // 未起飞，起飞后也只会到保护格子

    const target_pos = pos + dice;
    const pub_pos = Constants.priPos2PubPos(pos, side);
    const target_pub_pos = Constants.priPos2PubPos(target_pos, side);
    return Constants.GUARD_POSITIONS.indexOf(pub_pos) !== -1 &&
      Constants.GUARD_POSITIONS.indexOf(target_pub_pos) === -1;
  },
  // 移到敌机前方 N 个格子
  moveAheadOpponent(side, chesses, pos, dice, grids) {
    if (pos === -1) return false; // 排除未起飞的情况（虽然起点前 N 格也可能有敌机，但起飞后就处于保护格子）

    const target_pos = pos + dice;
    if (target_pos >= Constants.GRID_POSITIONS.length - 1) { // 排除可移到己方彩色通道的情况
      return false;
    }

    const target_pub_pos = Constants.priPos2PubPos(target_pos, side);
    if (Constants.GUARD_POSITIONS.indexOf(target_pub_pos) !== -1) { // 排除己方在保护格子的情况
      return false;
    }

    for (const symbol in chesses) {
      if (side === symbol) continue; // 排除己方

      for (const opponent_pos of chesses[symbol]) {
        if (opponent_pos === -1 || // 排除未起飞的敌机
            opponent_pos === -2 || // 排除已达终点的敌机
            Constants.isInTunnel(opponent_pos) || // 排除在彩色通道的敌机
            Constants.isInTunnel(opponent_pos + 1)) { // 排除往前一步就到彩色通道的敌机
          continue;
        }

        if (grids > 0) { // 处于敌机前面 N 格
          for (let i = 1; i <= grids; i++) {
            const opponent_pub_pos = Constants.priPos2PubPos(opponent_pos + i, symbol);
            if (target_pub_pos === opponent_pub_pos) {
              return true;
            }
          }
        } else if (grids < 0) { // 处于敌机后面 N 格
          for (let i = -1; i >= grids; i--) {
            const opponent_pub_pos = Constants.priPos2PubPos(opponent_pos + i, symbol);
            if (target_pub_pos === opponent_pub_pos) {
              return true;
            }
          }
        }
      }
    }

    return false;
  },
  evaluateScore(side, chesses, chessIndex, dice) {
    let score = 0;
    const pos = chesses[side][chessIndex]; // 按可行走棋子索引规则，pos !== -2
    if (this.canEat(side, chesses, pos, dice)) {
      score += 5000;
    }
    if (this.canMoveToEndPoint(pos, dice)) {
      score += 4500;
    }
    if (this.canLaunch(pos, dice)) {
      score += 4000;
    }
    if (this.canMoveToTunnel(pos, dice)) {
      score += 1400;
    }
    if (this.canMoveToGuard(side, pos, dice)) {
      score += 1200;
    }
    if (this.canMoveInTunnel(pos, dice)) {
      score += 1000;
    }
    if (this.runAway(side, chesses, pos)) {
      score += 500;
    }
    if (this.runAfter(side, chesses, pos)) {
      score += 500;
    }
    if (this.shiftOutGuard(side, pos, dice)) {
      score -= 700;
    }
    if (this.moveAheadOpponent(side, chesses, pos, dice, 6)) {
      score -= 300;
    }
    if (this.moveAheadOpponent(side, chesses, pos, dice, 12)) {
      score -= 100;
    }

    return score;
  },
  getBestChess(side, chesses, dice, chessIndices) {
    let best_score = -999999999;
    let best_index = -1;
    for (const chessIndex of chessIndices) {
      const score = this.evaluateScore(side, chesses, chessIndex, dice);
      const old_pos = chesses[side][chessIndex];
      const new_pos = old_pos + dice;
      console.log(`${Constants.SIDES[side]} 第 ${chessIndex} 个棋子 ` +
        `从 ${old_pos}（${Constants.priPos2PubPos(old_pos, side, true)}） ` +
        `移动至 ${new_pos} （${Constants.priPos2PubPos(new_pos, side, true)}）` +
        `评估得分：${score}（最高得分：${best_score}）`);

      if (score > best_score) {
        best_score = score;
        best_index = chessIndex;
      }
    }

    return best_index;
  },
};

export default LudoAI;
